package com.zws.cucumber.spring.configuration;

import com.datastax.oss.driver.api.core.CqlSession;
import com.zws.cucumber.adaptation.cass.ZwsCqlSessionProxy;
import com.zws.cucumber.bootstrap.ZwsCassBootstrap;
import com.zws.cucumber.snapshot.ZwsRemoteCassSnapshotManager;
import com.zws.cucumber.util.cass.ZwsCassContext;
import com.zws.cucumber.util.cass.ZwsCassTemplate;
import com.zws.cucumber.util.cass.backdoor.ZwsCassBackdoorClient;
import org.apache.commons.lang3.StringUtils;
import org.cassandraunit.utils.CqlOperations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;

import java.net.InetSocketAddress;
import java.util.List;

import static com.zws.cucumber.util.cass.ZwsCassContext.getGeneratedKeySpace;

/**
 * author: zws
 */
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ZwsCassConf implements EnvironmentAware {

    private static final Logger logger = LoggerFactory.getLogger(ZwsCassConf.class.getSimpleName());

    private volatile List<String> tables;
    private Environment environment;

    @Value("${ct.cucumber.database.clearEachCase:true}")
    private boolean clearEachCase;

    @Value("${ct.cucumber.database.creationScriptPath:cql/create-table.cql}")
    private String creationScriptPath;

    @Value("${ct.cucumber.database.dataScriptPath:cql/data.cql}")
    private String dataScriptPath;

    @Value("${ct.keyspace.name:zws}")
    private String keyspace;

    @Bean
    public ZwsCassContext cassandraServer() throws Exception {
        String generatedKeySpace = getGeneratedKeySpace(keyspace);
        System.setProperty("zws.cassandra.keySpace", generatedKeySpace);

        if (StringUtils.isBlank(creationScriptPath)) {
            creationScriptPath = environment.getProperty("ct.cucumber.database.creationScriptPath");
        }
        if (StringUtils.isBlank(dataScriptPath)) {
            dataScriptPath = environment.getProperty("ct.cucumber.database.dataScriptPath");
        }

        ZwsCommonConf.asyncInitResource(
                () -> ZwsCassBootstrap.getCassandraServer(creationScriptPath, dataScriptPath, generatedKeySpace));

        return new ZwsCassContext();
    }

    @Bean
    @DependsOn({"cassandraServer", "syncOnResourceAsyncInitPhase"})
    public ZwsCassBackdoorClient unsafeCassandraOperationClient() {
        return ZwsCassBootstrap.cassBackdoorClient;
    }

    @Bean
    public String keyspace() {
        return getGeneratedKeySpace(keyspace);
    }

    @Bean(destroyMethod = "destroy")
    @DependsOn({"cassandraServer", "syncOnResourceAsyncInitPhase"})
    @Order(Ordered.HIGHEST_PRECEDENCE + 20)
    public TestSessionFactory sessionFactory() {
        return new TestSessionFactory(ZwsCassContext.getSession(), clearEachCase);
    }

    @Bean
    @DependsOn("sessionFactory")
    public ZwsCassTemplate databaseTemplate(TestSessionFactory sessionFactory) {
        return ZwsCassContext.getCassTemplate();
    }

    @Bean
    public ZwsRemoteCassSnapshotManager remoteCassandraSnapshotManager(@Autowired(required = false) ZwsCassContext cassContext) {
        return new ZwsRemoteCassSnapshotManager(ZwsCassBootstrap.cassBackdoorClient);
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    public static class TestSessionFactory {

        private final CqlSession session;

        TestSessionFactory(CqlSession session, boolean clearEachCase) {
            this.session = buildSession(clearEachCase);
        }

        private CqlSession buildSession(boolean clearEachCase) {
            // keyspace?
            CqlSession session = CqlSession.builder()
                    .addContactPoint(InetSocketAddress.createUnresolved("127.0.0.1", ZwsCassContext.getCassandraPort()))
                    .withKeyspace(System.getProperty("zws.cassandra.keySpace"))
                    .withLocalDatacenter(ZwsCassContext.getLocalDc())
                    .build();
            CqlOperations.use(session).accept(System.getProperty("zws.cassandra.keySpace"));

            return ZwsCqlSessionProxy.create(session, clearEachCase);
        }

        public CqlSession getSession() {
            return session;
        }

        public void destroy() {
            if (session != null) {
                session.close();
            }
        }
    }

}
